package com.threadPool.pool;

import com.threadPool.enums.RejectedPolicy;
import com.threadPool.thread.CoreThread;
import com.threadPool.thread.WorkerThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class CommonThreadPool implements BaseThreadPool{
    private static final Logger logger = LoggerFactory.getLogger(MyThreadPool.class);
    private boolean allowCoreThreadTimeOut;
    // 超时时间配置
    private long timeOut;
    // 超时时间单位配置
    private final TimeUnit timeOutUnit;
    // 核心线程池大小配置
    private int coreThreadSize;
    // 工作线程池大小配置
    private int workerThreadSize;
    // 任务队列，采用BlockingDeque以支持并发操作
    private final BlockingDeque<Runnable> taskQueue;
    // 拒绝策略，当任务队列满时决定如何处理新任务
    private RejectedPolicy rejectedPolicy;
    // 核心线程列表，用于长期运行的任务处理
    private final List<CoreThread> coreThreadList = new ArrayList<>(8);
    // 工作线程列表，用于短期或临时任务处理
    private final List<WorkerThread> workerThreadList = new ArrayList<>(16);
    // 是否关闭线程池标志位
    private boolean shutdown;
    // 统计成功和失败的任务数量
    private AtomicInteger successCount = new AtomicInteger(0);
    private AtomicInteger failedCount = new AtomicInteger(0);
    // 记录每个任务的开始时间
    private final Map<Runnable, Long> taskStartTimeMap = new ConcurrentHashMap<>();
    // 记录当前活动线程数量
    private final AtomicInteger activeThreads = new AtomicInteger(0);

    /**
     * 构造一个自定义线程池
     *
     * @param timeOut 线程空闲时间
     * @param timeOutUnit 空闲时间的单位
     * @param coreThreadSize 核心线程数量
     * @param workerThreadSize 工作线程数量
     * @param taskQueueSize 任务队列大小
     * @param rejectedPolicy 拒绝策略，当任务队列满且工作线程达到最大值时，决定如何拒绝任务
     */
    public CommonThreadPool(long timeOut, TimeUnit timeOutUnit, int coreThreadSize, int workerThreadSize, int taskQueueSize, RejectedPolicy rejectedPolicy) {
        this.timeOut = timeOut;
        this.timeOutUnit = timeOutUnit;
        this.coreThreadSize = coreThreadSize;
        this.workerThreadSize = workerThreadSize;
        this.taskQueue = new LinkedBlockingDeque<>(taskQueueSize);
        this.rejectedPolicy = rejectedPolicy;
        this.shutdown = false;

        // 初始化核心线程
        for (int i = 0; i < coreThreadSize; i++) {
            CoreThread thread = new CoreThread().createThread(taskQueue);
            thread.setName("CoreThread-" + i);
            coreThreadList.add(thread);
            thread.start();
        }
    }
    @Override
    public void execute(Runnable task) {
        if (task == null) throw new NullPointerException("task is null");
        // 尝试将任务加入队列
        if (taskQueue.offer(task) && !shutdown) {
            // 检查是否需要创建工作线程
            if (taskQueue.size() > coreThreadSize && workerThreadSize > workerThreadList.size()) {
                WorkerThread thread = new WorkerThread().createThread(taskQueue, timeOut, timeOutUnit);
                workerThreadList.add(thread);
                thread.setName("WorkerThread-" + workerThreadList.indexOf(thread));
                thread.start();
            }
        } else {
            // 队列已满，触发拒绝策略
            int totalThreads = coreThreadList.size() + workerThreadList.size();
            rejectedPolicy.rejected(
                    task,
                    taskQueue,
                    new AtomicInteger(totalThreads)
            );
        }
    }

    /**
     * 关闭所有线程并终止本系统
     * 此方法会一直等待直到任务队列为空，然后停止所有核心线程和工作线程
     */
    @Override
    public void shutdown() {
        shutdown = true; // 设置标志位
        while (true) {
            if (taskQueue.isEmpty()) {
                for (CoreThread thread : coreThreadList) {
                    thread.stopThread();
                }
                for (WorkerThread thread : workerThreadList) {
                    thread.stopThread();
                }
                break;
            }
        }
    }

    /**
     * 立即关闭线程池，并尝试停止所有正在执行的任务
     * 此方法会遍历核心线程列表和工作线程列表，分别调用它们的stopThread方法来停止线程
     * 同时，为了防止新的任务被提交，此方法还会清除任务队列中的所有任务
     */
    @Override
    public void shutdownNow() {
        shutdown = true; // 设置标志位
        for (CoreThread thread : coreThreadList) {
            thread.stopThread();
        }
        for (WorkerThread thread : workerThreadList) {
            thread.stopThread();
        }
        taskQueue.clear();
    }
    @Override
    public synchronized void setCorePoolSize(int newCoreSize) {
        if (newCoreSize < 0) throw new IllegalArgumentException("coreSize <0");

        int currentCore = coreThreadList.size();
        if (newCoreSize > currentCore) {
            for (int i = currentCore; i < newCoreSize; i++) {
                CoreThread thread = new CoreThread().createThread(taskQueue);
                coreThreadList.add(thread);
                thread.start();
            }
        } else if (newCoreSize < currentCore) {
            for (int i = currentCore - 1; i >= newCoreSize; i--) {
                CoreThread thread = coreThreadList.remove(i);
                thread.stopThread();
            }
        }
        this.coreThreadSize = newCoreSize; // 同步更新配置值
    }
    @Override
    public synchronized void setMaximumPoolSize(int newMaxSize) {
        if (newMaxSize < coreThreadSize)
            throw new IllegalArgumentException("maxSize must > coreSize");

        int currentMax = workerThreadList.size() + coreThreadList.size();
        if (newMaxSize > currentMax) {
            int needAdd = newMaxSize - currentMax;
            for (int i = 0; i < needAdd; i++) {
                WorkerThread thread = new WorkerThread()
                        .createThread(taskQueue, timeOut, timeOutUnit);
                workerThreadList.add(thread);
                thread.start();
            }
        } else if (newMaxSize < currentMax) {
            int needRemove = currentMax - newMaxSize;
            for (int i = 0; i < needRemove; i++) {
                WorkerThread thread = workerThreadList.remove(workerThreadList.size() - 1);
                thread.stopThread();
            }
        }
        this.workerThreadSize = newMaxSize - coreThreadSize; // 计算工作线程容量
    }
    @Override
    public void setKeepAliveTime(long time, TimeUnit unit) {
        if (time < 0) throw new IllegalArgumentException("time < 0");
        if (unit == null) throw new NullPointerException("unit is null");
        this.timeOut = time;
    }
    @Override
    public void setRejectedExecutionHandler(RejectedPolicy handler) {
        this.rejectedPolicy = handler;
    }

    /**
     * 设置是否允许核心线程超时
     * @param value 是否允许核心线程超时
     */
    @Override
    public void allowCoreThreadTimeOut(boolean value) {
        this.allowCoreThreadTimeOut = value;
        if (value) {
            for (CoreThread thread : coreThreadList) {
                thread.stopThread();
            }
        }
        if (!value) {
            for (CoreThread thread : coreThreadList) {
                thread.start();
            }
        }
    }
    @Override
    public int getCorePoolSize() {
        return coreThreadList.size();
    }
    @Override
    public int getMaximumPoolSize() {
        return workerThreadList.size();
    }
    @Override
    public long getKeepAliveTime(TimeUnit unit) {
        return timeOut;
    }
    @Override
    public BlockingDeque<Runnable> getQueue() {
        return taskQueue;
    }
    @Override
    public RejectedPolicy getRejectedExecutionHandler() {
        return rejectedPolicy;
    }
    @Override
    public boolean allowsCoreThreadTimeOut() {
        return allowCoreThreadTimeOut;
    }
    @Override
    public void beforeExecute(Thread t, Runnable task) {
        // 在任务开始执行前增加活跃线程计数
        activeThreads.incrementAndGet();
        long startTime = System.currentTimeMillis();
        taskStartTimeMap.put(task, startTime); // 新增：记录开始时间

        // 1. 任务基础信息
        String taskName = task.getClass().getSimpleName();
        String threadName = t.getName();

        // 2. 线程池状态
        int activeThreads = getActiveThreads(); // 需要实现线程活跃数统计
        int queueSize = taskQueue.size();

        // 3. 系统资源（可选）
        // Runtime runtime = Runtime.getRuntime();
        // long freeMemory = runtime.freeMemory();

        // 示例日志输出
        logger.info("任务开始执行: task={}, com.threadPool.thread={}, activeThreads={}, queueSize={}, startTime={}",
                taskName, threadName, activeThreads, queueSize, startTime);
    }
    @Override
    public int getActiveThreads() {
        return activeThreads.get();
    }
    @Override
    public void afterExecute(Runnable task, Throwable thrown) {
        activeThreads.decrementAndGet();
        long endTime = System.currentTimeMillis();

        if (task == null) {
            logger.error("任务为空，无法记录详细信息");
            return;
        }

        long duration = endTime - getTaskStartTime(task);
        String status = thrown != null ? "失败" : "成功";

        if (thrown != null) {
            failedCount.incrementAndGet();
            logger.error("任务执行异常: task={}, error={}",
                    task.getClass().getSimpleName(), thrown.getMessage());
        } else {
            successCount.incrementAndGet();
        }

        logger.info("任务执行完成: task={}, status={}, duration={}ms",
                task.getClass().getSimpleName(), status, duration);
    }

    private long getTaskStartTime(Runnable task) {
        return taskStartTimeMap.getOrDefault(task, 0L);
    }
}
